package com.snowruin.redisson.lock.spring.boot.starter;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;

import com.snowruin.distributed.lock.common.utils.SPELUtils;
import com.snowruin.redisson.lock.spring.boot.starter.annotation.RedissonLockHandler;
import com.snowruin.redisson.lock.spring.boot.starter.enums.RedissonLockType;
import com.snowruin.redisson.lock.spring.boot.starter.exception.RedissonDistributedLockException;

@Aspect
@Configuration
@ConditionalOnBean(RedissonClient.class)
@AutoConfigureAfter(RedissonAutoConfiguration.class)
public class RedissonDistributedLockAspectConfiguration {

	private  Logger logger = LoggerFactory.getLogger(RedissonDistributedLockAspectConfiguration.class);
	
	@Autowired
	private  RedissonClient redissonClient;
	
	@Around("@annotation(com.snowruin.redisson.lock.spring.boot.starter.annotation.RedissonLockHandler)")
	public Object exec(ProceedingJoinPoint proceedingJoinPoint) throws InterruptedException {
		
		// 获取方法
		Method method = ((MethodSignature)proceedingJoinPoint.getSignature()).getMethod();
		RedissonLockHandler annotation = method.getAnnotation(RedissonLockHandler.class);
		String key = annotation.value();
		key = SPELUtils.parser(key, method, proceedingJoinPoint.getArgs());
		
		RLock lock = this.getLock(key, annotation);
		if(!lock.tryLock(annotation.waitTIme(), annotation.leaseTime(), annotation.timeUnit())) {
			logger.info("未获取到锁，返回null");
			return null;
		}
		
		
		logger.info("获取到锁了，继续执行");
		
		try {
			Object result = proceedingJoinPoint.proceed();
			return result;
		} catch (Throwable e) {
			logger.info("执行业务代码时发生了异常");
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
		return null;
	}
	
	private RLock getLock(String key , RedissonLockHandler redissonLockHandler) {
		RedissonLockType type = redissonLockHandler.type();
		RLock lock = null ;
		switch (type) {
		case FAIR_LOCK:
			lock = this.redissonClient.getFairLock(key);
			break;
		case REENTRANT_LOCK:
			lock = this.redissonClient.getLock(key);
			break;
		case READ_LOCK:
			lock = this.redissonClient.getReadWriteLock(key).readLock();
			break;
			
		case WRITE_LOCK:
			lock = this.redissonClient.getReadWriteLock(key).writeLock();
			break;
		default:
			throw new RedissonDistributedLockException("获取锁时发生异常，所类型为 ： " + redissonLockHandler.type().name());
		}
		return lock;
	}

	
}
